#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import traceback
import copy
from Ump.objs.session_wrapper import _sw
from flask import request
from flask import session as flask_session

# import tornado
# from repoze.lru import lru_cache

from Ump.common.checker import Validator


reload(sys)
sys.setdefaultencoding('utf-8')

from Ump import webutil
from Ump.common.utils import inspect_func
from Ump.objs.token.manager import TokenManager
from Ump.objs.session_wrapper import _sw

from flask.views import MethodView


def add_manager(manager):
    def wrapper(cls):
        cls.MANAGER = manager
        return cls
    return wrapper


class BaseHandler(MethodView):
    MANAGER = None

    _post_params = {
        'need': [],
        'optional': [],
    }
    _delete_params = {
        'need': [],
        'optional': [],
    }
    _put_params = {
        'need': [],
        'optional': [],
    }
    _get_params = {
        'need': [],
        'optional': [
            'skip',
            'limit',
            'order',
            'desc',
        ],
    }

    def __init__(self):
        self._json = {}
        self.find_spec = {
            'spec': {},
            'skip': 0,
            'limit': 10,
            'order': None,
            'desc': False,
        }
        
        self.custom_data = self.__get_request_data()

    def __get_request_data(self):
        custom_data = {}
        if request.json:
            custom_data.update(request.json)
        if request.form:
            custom_data.update(request.form.to_dict())
        if request.args:
            custom_data.update(request.args.to_dict())
        return custom_data

    @property
    def params_spec(self):
        res = request.method
        method = res.lower()
        return getattr(self, '_%s_params' % method, {})

    def check_params(self):
        res = {}

        _json = self.custom_data
        spec = self.params_spec

        def parse_name(name):
            if isinstance(name, tuple):
                name, check_name = name
            else:
                check_name = name
            return name, check_name

        for name in spec.get('need', []):
            name, check_name = parse_name(name)
            value = _json.get(name)
            if value is None:
                raise ValueError('%s是必需参数' % name)
            res[name] = Validator.check(check_name, value)

        for name in spec.get('optional', []):
            # TODO CHECK default value
            name, check_name = parse_name(name)
            value = _json.get(name)
            if value is not None:
                res[name] = Validator.check(check_name, value)

        return res

    def prepare_input(self):
        self.custom_data.update(dict(skip=0, limit=None, order=None, desc=False))
        _json = self.custom_data
        self._json = _json

        # TODO spec
        spec = {}
        for k, v in _json.iteritems():
            if k not in ['skip', 'limit', 'order', 'desc', 'op_user_id']:
                spec[k] = v

        self.find_spec = {
            'spec': spec,
            'skip': int(_json['skip']),
            'limit': _json['limit'],
            'order': _json['order'],
            'desc': _json['desc'],
        }
        return self.find_spec

    def current_user(self):

        value = request.headers.get('X-Authorization')
        if isinstance(value, (str, unicode)):
            # format: TOKEN=xxx
            idx = value.find('=')
            if idx != -1:
                token_name = value[idx+1:]
                token = TokenManager.load(token_name)

                flask_session['token'] = copy.deepcopy(token)

                return token
        return None

    @inspect_func
    def _POST(self, *args, **kw):
        if 'params' in kw:
            _json = kw['params']
        else:
            _json = self.custom_data
            _json.update(kw)
        n = len(args)
        if n == 0:
            return self._run_func('create', _json)
        elif n == 1:
            _id = args[0]
            _json.update(id=_id)
            return self._run_func('update', _json)
        elif n == 2:
            _id, op = args
            _json.update(id=_id)
            return self._run_func(op, _json)

    @inspect_func
    def _DELETE(self, *args, **kw):
        _json = self.custom_data
        n = len(args)
        if n == 1:
            _id = args[0]
            _json.update({'id': _id})
            return self._run_func('delete', _json, skip2dict=True)
        return self._echo(_json)

    def _GET(self, _id=None):
        #web.header('Content-Type', 'application/ump-v3+json')
        model = self.MANAGER.MODEL
        if _id:
            return webutil.web_return(_sw.get_one, model=model, id_or_spec=_id)
        else:
            find_spec = self.prepare_input()
            return webutil.web_return(_sw.get_list, model=model, **find_spec)

    @webutil.authenticated(auth=False)
    def get(self, *args, **kw):
        _id = kw.get('_id')
        if _id:
            return self._GET(_id=_id)
        else:
            return self._GET()
        # print '@@@@@@@@@@@@@@@@@@@@@@@@', args, kw
        # n = len(args)
        # if n == 1:
        #     _id = args[0]
        #     return self._GET(_id=_id)
        # else:
        #     return self._GET()

    @inspect_func
    def _run_func(self, func_name, _json, **kw):
        # TODO
        if func_name in ['get_pool', 'get_volume', 'get_snapshot', 'get_vgroup', 'get_cgsnapshot', 'get_folder', 'get_qos']:
            func = getattr(_sw, func_name)
            return webutil.web_return(func, _json, **kw)
        else:
            func = getattr(self.MANAGER, func_name)
            return webutil.web_return(func, _json, **kw)

    def _echo(self, _json):
        return webutil.success2json(_json)
